package ffte.core.mixed

import spinal.core._
import spinal.lib._

import ffte.types.{VecComplex,FixComplex}
import ffte.core.samewidthed
import ffte.property.{getFFTIW,getFFTOW,getTwiddleResolution}
import ffte.core.streamed.{streamedComponents}

/**
 * Twiddle factor rotator for mixed FFT implementations
 *
 * This component implements complex multiplication with twiddle factors
 * required by Cooley-Tukey based FFT decompositions in mixed architecture.
 * The rotator supports different indexing patterns based on the rgen flag
 * and uses ROM-based twiddle factor storage for efficiency.
 *
 * Architecture Features:
 * - Streaming interface with backpressure support
 * - ROM-based twiddle factor storage for resource efficiency
 * - Configurable indexing patterns for different decomposition strategies
 * - Fixed-point arithmetic with precision management
 * - Pipeline registers for timing optimization
 *
 * Twiddle Factor Generation:
 * - Uses exponential complex number generation for precise values
 * - Supports both rgen and non-rgen indexing patterns
 * - Optimized precision for hardware implementation
 * - Pre-computed values stored in ROM for fast access
 *
 * @param dW Data width for input/output complex numbers
 * @param first First permutation table from FFT decomposition
 * @param second Second permutation table from FFT decomposition
 * @param rgen Flag indicating reverse generation indexing mode
 */
class rotator(val dW: Int, first: Array[Int], second: Array[Int], rgen: Boolean) extends streamedComponents with samewidthed {
    /** Standard streaming I/O interface */
    val io = iogen

    /**
     * Flow control: Backpressure propagation
     *
     * Output ready directly controls input ready for direct
     * backpressure path preventing buffer overflow.
     */
    io.d.ready := io.q.ready

    /**
     * Transaction firing condition
     *
     * A transaction fires when both input valid and output ready
     * are asserted, indicating successful data transfer.
     */
    val fire = io.d.fire

    /**
     * Output valid signal generation
     *
     * Output becomes valid when the current transaction fires,
     * ensuring proper handshaking.
     */
    io.q.valid := fire

    /** Twiddle factor width (reduced precision for optimization) */
    val tW = 1 - getTwiddleResolution()

    /** Twiddle factor resolution (fractional bits) */
    val tr = getTwiddleResolution()

    /** Twiddle table size based on indexing mode */
    val N = if (rgen) first.size else second.size

    /** Total transform size for twiddle factor calculation */
    val rN = first.size * second.size

    /**
     * Input data register
     *
     * Stores the input complex data when transaction fires.
     * Uses Register-Next-When for proper timing control.
     */
    val d = RegNextWhen(io.d.payload.fragment, fire)

    /**
     * Twiddle factor address counter
     *
     * Cycles through twiddle factor table entries.
     * Clears on last signal to maintain synchronization.
     */
    val cnt = Counter(N, inc = fire)

    /**
     * Generate twiddle factor table
     *
     * Creates a table of complex twiddle factors with optimized indexing.
     * The indexing pattern depends on the rgen flag for different
     * decomposition strategies.
     */
    def ttab = for (n <- 0 until N) yield {
        val r = VecComplex(G, tW, tr)
        for (g <- 0 until G) {
            r.d(g) := (if (rgen)
                FixComplex(tW, tr).expj(-second(g) * first(n), rN)
            else
                FixComplex(tW, tr).expj(-second(n) * first(g), rN))
        }
        r
    }

    /**
     * Twiddle factor ROM memory
     *
     * Stores pre-computed twiddle factors for efficient access.
     * ROM-based storage saves DSP resources compared to
     * runtime calculation.
     */
    val mem = Mem(VecComplex(G, tW, tr), initialContent = ttab)

    /**
     * Synchronous ROM read
     *
     * Reads twiddle factors from ROM with synchronous timing.
     * Address comes from counter for sequential access.
     */
    val f = mem.readSync(
        address = cnt,
        enable = fire
    )

    /**
     * Output result register
     *
     * Stores the result of complex multiplication between
     * input data and twiddle factors.
     */
    val q = RegInit(VecComplex(G, dW + tW, d.resolution + tr).zero)

    /**
     * Complex multiplication pipeline
     *
     * Performs complex multiplication and counter management
     * when transaction fires.
     */
    when(fire) {
        when(io.d.payload.last) {
            cnt.clear  // Reset counter on burst completion
        }
        q := d * f    // Complex multiplication: input * twiddle
    }

    /**
     * Output precision management
     *
     * Cuts the result back to the target precision with proper
     * scaling to maintain accuracy.
     */
    io.q.payload.fragment := q.cut(dW, -tr - 1, d.resolution)

    /**
     * Component delay in clock cycles
     *
     * Fixed delay of 2 cycles for pipelined operation:
     * - Cycle 1: ROM read and input register
     * - Cycle 2: Complex multiplication and output register
     */
    def delay = 2

    /**
     * Last signal propagation
     *
     * Delays the last signal to match the computational latency
     * and maintain proper burst boundaries.
     */
    io.q.payload.last := Delay(io.d.payload.last, delay, fire)
}